; glue.s

        AREA    |NewFS_Support|,CODE,READONLY

;****************************************************************************

TRACE_UPCALLS    EQU  0              ; must also set TRACE_UPCALLS in newfs.h

;****************************************************************************

        IMPORT  |_Lib$Reloc$Off|
        IMPORT  |Image$$RO$$Base|
        IMPORT  |_syserr|

        EXPORT  |module_name|
        EXPORT  |module_base|
        EXPORT  |write_word|
        EXPORT  |load_word|
        EXPORT  |validate_buffer|

; FileSwitch interface functions

        EXPORT  |NewFS_Open|
        EXPORT  |NewFS_GetBytes|
        EXPORT  |NewFS_PutBytes|
        EXPORT  |NewFS_Args|
        EXPORT  |NewFS_Close|
        EXPORT  |NewFS_File|
        EXPORT  |NewFS_Func|

;****************************************************************************

; Standard register names

r0      RN      0
r1      RN      1
r2      RN      2
r3      RN      3
r4      RN      4
r5      RN      5
r6      RN      6
r7      RN      7
r8      RN      8
r9      RN      9
r10     RN      10
r11     RN      11
r12     RN      12
r13     RN      13
r14     RN      14
r15     RN      15

;****************************************************************************

; standard C register definitions

a1      RN      0
a2      RN      1
a3      RN      2
a4      RN      3
av      RN      4
;v1      RN      5
;v2      RN      6
;v3      RN      7
;v4      RN      8
;v5      RN      9

sl      RN      10
fp      RN      11
ip      RN      12
sp      RN      13
lk      RN      14
pc      RN      15

;****************************************************************************

; ARM processor flags

        MACRO
$label  bit     $shift
$label  *       (1 :SHL: $shift)
        MEND

Nbit    bit     31
Zbit    bit     30
Cbit    bit     29
Vbit    bit     28
Ibit    bit     27
Fbit    bit     26

;****************************************************************************

        MACRO
$label  CLRV    $cond            ; Clear overflow flag
$label  CMP$cond pc, #0
        MEND

        MACRO
$label  SETV    $cond            ; Set overflow flag
$label  CMP$cond pc, #&80000000
        MEND

;****************************************************************************

; Call the given C routine (returns with V set if (a1 == -1) return).
; r12 = private word pointer.
; a1,a2,a3,a4,av,v1,v2,v3 available as parameters.
; Requires the label "not_enough_stack" to be defined for the
; filing system.
; The location "sl_offset" should contain the label "_Lib$Reloc$Off".
; The location "_errptr" should contain the label "_syserr".

free_stack      *       &00000400       ; 1K minimum stack size
        MACRO
$label  Ccall   $address,$pushnumber,$pushstack
$label
        STMFD   sp!,{sl,fp,lk}          ; preserve entry state
        MOV     sl,sp,LSR #20           ; sl = MByte boundary below sp
        MOV     sl,sl,LSL #20           ; sl = real stack limit
        SUB     fp,sp,sl                ; fp = number of free bytes
        CMP     fp,#free_stack          ; minimum size of stack
        LDMCCFD sp!,{sl,fp,lk}          ; recover entry registers
        BCC     NewFS_not_enough_stack    ; and complain to the user
        LDMIA   sl,{v4,v5}              ; stack-frame description
;        LDR     r12,[r12],#&00          ; load private word contents
        LDR     r12,[r12]               ; load private word contents
        LDMIB   r12,{r11,r12}           ; load stack-frame description
        STMIA   sl,{r11,r12}            ; and store at stack-limit
        ADRL    lk,sl_offset
        LDR     lk,[lk,#&00]            ; size of stack overflow buffer
        ADD     sl,sl,lk                ; add on stack overflow buffer
        MOV     fp,#&00000000           ; no frame-pointer
        ; stack items if the user has requested so
        [       ("$pushnumber" <> "")
        [       ("$pushstack" <> "") :LAND: ($pushnumber <> 0)
        STMFD   sp!,{$pushstack}
        ]
        ]
        BL      $address
        ; recover stack items if the user pushed any
        [       ("$pushnumber" <> "")
        [       ("$pushstack" <> "") :LAND: ($pushnumber <> 0)
        ADD     sp,sp,#($pushnumber * 4)
        ]
        ]
        ADRL    lk,sl_offset
        LDR     lk,[lk,#&00]            ; stack overflow buffer
        CMP     r0,#&FFFFFFFF           ; (-1) == error state
        ADREQL  r0,|_errptr|
        LDREQ   r0,[r0,#&00]            ; offset in static data area
        SUBEQ   lk,sl,lk
        LDREQ   fp,[lk,#&04]            ; reference our static data
        ADDEQ   r0,fp,r0                ; reference the pointer
        LDREQ   r0,[r0,#&00]            ; and load the pointer
        ; -- This code should NOT update the PSR ----------------------------
        ADRL    lk,sl_offset
        LDR     lk,[lk,#&00]            ; stack overflow buffer
        SUB     sl,sl,lk                ; recover true stack-limit
        STMIA   sl,{v4,v5}              ; and restore stack-limit contents
        LDMFD   sp!,{sl,fp,lk}          ; recover entry state
        ; -------------------------------------------------------------------
        BEQ     %FT00                   ; error    = V set
        ; no error = V clear
        CLRV
        B       %FT01
00      ; error = V set
        SETV
01      ; exit with V reflecting error state
        MEND

;****************************************************************************

; Errors

notsupported    *       &D8
nostack         *       &A5
badparargs      *       &00
badparfile      *       &01
badparfunc      *       &02

;****************************************************************************

; private (assembler) data

sl_offset       &       |_Lib$Reloc$Off|        ; stack overflow buffer size
|_errptr|       &       |_syserr|               ; pointer to error block
|module_base|   &       |Image$$RO$$Base|       ; module base address

;****************************************************************************

modulename
        =       "NewFS",&00                     ; module name
        ALIGN

;****************************************************************************

; char *module_name(void)
; Return the name of our module to the caller.

module_name
        ADRL    a1,modulename
        MOVS    pc,lk

;****************************************************************************

        LTORG

;****************************************************************************

; Filing System interface:

        IMPORT  |NewFS_open_file|      ; open a file
        IMPORT  |NewFS_get_bytes|      ; read bytes from an open file
        IMPORT  |NewFS_put_bytes|      ; write bytes to an open file
        IMPORT  |NewFS_close_file|     ; close an open file

        IMPORT  |NewFS_write_extent|   ; write file extent 
        IMPORT  |NewFS_alloc|          ; read size allocated to file 
        IMPORT  |NewFS_flush|          ; flush file buffer 
        IMPORT  |NewFS_ensure|         ; ensure file size 
        IMPORT  |NewFS_write_zeros|    ; write zeros to file
        IMPORT  |NewFS_read_datestamp| ; read load/exec addrs of open file

        IMPORT  |NewFS_save_file|      ; save a complete file image
        IMPORT  |NewFS_read_cat|       ; read catalogue information
        IMPORT  |NewFS_write_cat|      ; write catalogue information 
        IMPORT  |NewFS_delete|         ; delete object 
        IMPORT  |NewFS_create|         ; create file 
        IMPORT  |NewFS_create_dir|     ; create directory 
        IMPORT  |NewFS_read_block_size|; return natural block size for image

        IMPORT  |NewFS_rename|            ; rename object 
        IMPORT  |NewFS_read_dir|          ; read directory entries 
        IMPORT  |NewFS_read_dir_info|     ; read directory entries and info
        IMPORT  |NewFS_image_open|        ; notification of image file open
        IMPORT  |NewFS_image_close|       ; notification of image file close
        IMPORT  |NewFS_defect_list|       ; generate defect list for image
        IMPORT  |NewFS_add_defect|        ; add a defect into the list
        IMPORT  |NewFS_read_boot_option|  ; read boot option
        IMPORT  |NewFS_write_boot_option| ; write boot option
        IMPORT  |NewFS_used_space_map|    ; generate space map
        IMPORT  |NewFS_read_free_space|   ; return free space information
        IMPORT  |NewFS_namedisc|          ; namedisc
        IMPORT  |NewFS_stampimage|        ; update the image identity
        IMPORT  |NewFS_objectatoffset|    ; return name of object at offset

        IMPORT  |global_error|            ; generate error message

;****************************************************************************

NewFS_Open
                        ; a1 == r0      type of open to perform
                        ; a2 == r1      pointer to NULL terminated filename
        MOV     a3,r6   ; a3 == r6      image handle for this file
        Ccall   |NewFS_open_file|
        ORRVSS  pc,lk,#Vbit             ; error -> r0 = ptr to error block
        LDMIA   r0,{r0-r4}              ; r0 = pointer to information block
        ; r0 == file information word
        ; r1 == filing system handle (0 = "not found")
        ; r2 == buffer size (0 if file is unbuffered, 2^n (n = 6..10))
        ; r3 == file extent (buffered files only)
        ; r4 == current file allocation (in buffer size multiples)
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_GetBytes
        MOV     a1,r1           ; r1 = filing system handle
        MOV     a2,r2           ; r2 = memory address for data
        MOV     a3,r3           ; r3 = number of bytes to transfer
        MOV     a4,r4           ; r4 = file offset (PTR#)
        Ccall   |NewFS_get_bytes|
        ; r0 = byte read if unbuffered
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_PutBytes
        MOV     r7,r0           ; preserve the byte to be written
        MOV     a1,r1           ; r1 = filing system handle
        MOV     a2,r2           ; r2 = memory address of data
        MOV     a3,r3           ; r3 = number of bytes to transfer
        MOV     a4,r4           ; r4 = file offset (PTR#)
        Ccall   |NewFS_put_bytes|,1,r7
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_Close
        MOV     a1,r1           ; r1 = filing system handle
        MOV     a2,r2           ; r2 = new load address for file
        MOV     a3,r3           ; r3 = new exec address for file
        Ccall   |NewFS_close_file|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_Args

; r0 reason code:
; &03 = write file extent (|NewFS_write_extent|)
;       in:     r1 = filing system handle
;               r2 = new file extent
;       out:    no conditions
;
; &04 = read size allocated to file (|NewFS_alloc|)
;       in:     r1 = filing system handle
;       out:    r2 = size allocated to file by filing system
;
; &06 = flush file buffer (|NewFS_flush|)
;       in:     r1 = filing system handle
;       out:    r2 = load address of file (or 0)
;               r3 = exec address of file (or 0)
;
; &07 = ensure file size (|NewFS_ensure|)
;       in:     r1 = filing system handle
;               r2 = size of file to ensure
;       out:    r2 = size of file actually ensured
;
; &08 = write zeroes to file (|NewFS_write_zeros|)
;       in:     r1 = file handle
;               r2 = file address to write zeros at
;               r3 = number of zeros to write
;
; &09 = read load/exec addresses (|NewFS_read_datestamp|)
;       in:     r1 = file handle
;       out:    r2 = load address of file
;               r3 = execute address of file

        CMP     r0,#args_table_entries
        BGT     NewFS_args_badparameter
        ADD     pc,pc,r0,LSL #2
        &       0                      ; DO NOT REMOVE OR ADD CODE
args_table_start
        B       NewFS_notsupported                ; 00 / 0
        B       NewFS_notsupported                ; 01 / 1
        B       NewFS_notsupported                ; 02 / 2
        B       |call_NewFS_write_extent|         ; 03 / 3
        B       |call_NewFS_alloc|                ; 04 / 4
        B       NewFS_notsupported                ; 05 / 5
        B       |call_NewFS_flush|                ; 06 / 6
        B       |call_NewFS_ensure|               ; 07 / 7
        B       |call_NewFS_write_zeros|          ; 08 / 8
        B       |call_NewFS_read_datestamp|       ; 09 / 9
args_table_end
args_table_entries      *       ((args_table_end - args_table_start) / 4)

NewFS_args_badparameter
        MOV     a1,#badparargs
        Ccall   |global_error|
        ORRS    pc,lk,#Vbit

|call_NewFS_write_extent|
        MOV     a1,r1                   ; filing system handle
        MOV     a2,r2                   ; new file extent
        Ccall   |NewFS_write_extent|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_alloc|
        MOV     a1,r1                   ; filing system handle
        Ccall   |NewFS_alloc|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_flush|
        MOV     a1,r1                   ; filing system handle
        Ccall   |NewFS_flush|
        ORRVSS  pc,lk,#Vbit
        LDMIA   r0,{r2,r3}
        BICS    pc,lk,#Vbit

|call_NewFS_ensure|
        MOV     a1,r1                   ; filing system handle
        MOV     a2,r2                   ; size to ensure
        Ccall   |NewFS_ensure|
        ORRVSS  pc,lk,#Vbit
        MOV     r2,a1                   ; actual size ensured
        BICS    pc,lk,#Vbit

|call_NewFS_write_zeros|
        MOV     a1,r1                   ; filing system handle
        MOV     a2,r2                   ; offset within file
        MOV     a3,r3                   ; number of zeros to write
        Ccall   |NewFS_write_zeros|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_read_datestamp|
        MOV     a1,r1                   ; filing system handle
        Ccall   |NewFS_read_datestamp|
        ORRVSS  pc,lk,#Vbit
        LDMIA   r0,{r2,r3}
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_File

; r0 reason code:
;
; &00 = save file (|NewFS_save_file|)
;       in:     r1 = pointer to NULL terminated filename
;               r2 = load address of file
;               r3 = exec address of file
;               r4 = start address in memory of data
;               r5 = end address in memory (plus one)
;               r6 = filing system image handle
;       out:    r6 = pointer to leafname (*OPT 1 n printing)
;
; &01 = write catalogue information (|NewFS_write_cat|)
;       in:     r1 = pointer to NULL terminated wildcarded filename
;               r2 = load address to associate with file
;               r3 = exec address to associate with file
;               r5 = attributes to associate with file
;               r6 = filing system image handle
;       out:    no conditions
;
; &05 = read catalogue information (|NewFS_read_cat|)
;       in:     r1 = pointer to NULL terminated wildcarded filename
;               r6 = filing system image handle
;       out:    r0 = object type
;               r2 = load address
;               r3 = exec address
;               r4 = file length
;               r5 = file attributes
;
; &06 = delete object (|NewFS_delete|)
;       in:     r1 = pointer to NULL terminated filename
;               r6 = filing system image handle
;       out:    r0 = object type
;               r2 = load address
;               r3 = exec address
;               r4 = file length
;               r5 = file attributes
;
; &07 = create file (|NewFS_create|)
;       in:     r1 = pointer to NULL terminated filename
;               r2 = load address to associate with file
;               r3 = exec address to associate with file
;               r4 = length
;               r6 = filing system image handle
;       out:    no conditions
;
; &08 = create directory (|NewFS_create_dir|)
;       in:     r1 = pointer to NULL terminated directory name
;               r2 = load address (new feature)
;               r3 = exec address (new feature)
;               r4 = number of entries (0 for default)
;               r6 = filing system image handle
;       out:    no conditions
;
; &0A = read block size (|NewFS_read_block_size|)
;       in:     r1 = pointer to NULL terminated file name
;               r6 = filing system image handle
;       out:    r2 = natural block size of the file in bytes

        CMP     r0,#file_table_entries
        BGT     NewFS_file_badparameter
        ADD     pc,pc,r0,LSL #2
        &       0              ; DO NOT REMOVE OR ADD CODE
file_table_start
        B       |call_NewFS_save_file|            ; 00 / 0
        B       |call_NewFS_write_cat|            ; 01 / 1
        B       NewFS_notsupported                ; 02 / 2
        B       NewFS_notsupported                ; 03 / 3
        B       NewFS_notsupported                ; 04 / 4
        B       |call_NewFS_read_cat|             ; 05 / 5
        B       |call_NewFS_delete|               ; 06 / 6
        B       |call_NewFS_create|               ; 07 / 7
        B       |call_NewFS_create_dir|           ; 08 / 8
        B       NewFS_notsupported                ; 09 / 9
        B       |call_NewFS_read_block_size|      ; 0A / 10
file_table_end
file_table_entries      *       ((file_table_end - file_table_start) / 4)

NewFS_file_badparameter
        MOV     a1,#badparfile
        Ccall   |global_error|
        ORRS    pc,lk,#Vbit

|call_NewFS_save_file|
        MOV     a1,r1                      ; filename
        MOV     a2,r2                      ; load address
        MOV     a3,r3                      ; exec address
        MOV     a4,r4                      ; start address
        Ccall   |NewFS_save_file|,2,r5-r6  ; end addr and filing system ihand
        ORRVSS  pc,lk,#Vbit
        MOV     r6,a1                      ; "*OPT 1 n" leafname
        BICS    pc,lk,#Vbit

|call_NewFS_write_cat|
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; load address
        MOV     a3,r3                   ; exec address
        MOV     a4,r5                   ; attributes
        Ccall   |NewFS_write_cat|,1,r6  ; filing system image handle
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_read_cat|
        MOV     a1,r1                   ; filename
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_read_cat|
        ORRVSS  pc,lk,#Vbit
        ; r0 = pointer to structure containing return information
        LDMIA   r0,{r0,r2-r5}           ; r6 should be preserved
        BICS    pc,lk,#Vbit

|call_NewFS_delete|
        MOV     a1,r1                   ; filename
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_delete|
        ORRVSS  pc,lk,#Vbit
        ; r0 = pointer to structure containing return information
        LDMIA   r0,{r0,r2-r5}
        BICS    pc,lk,#Vbit

|call_NewFS_create|
        [       {TRUE}  ; documentation seems to be wrong
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; load address
        MOV     a3,r3                   ; exec address
        MOV     a4,r4                   ; start address
        Ccall   |NewFS_create|,2,r5-r6  ; end addr and filing system ihand
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit
        |
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; load address
        MOV     a3,r3                   ; exec address
        MOV     a4,r4                   ; length
        Ccall   |NewFS_create|,1,r6     ; filing system image handle
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit
        ]       ; EOF {boolean}

|call_NewFS_create_dir|
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; r2 = load address
        MOV     a3,r3                   ; r3 = exec address
        MOV     a4,r4                   ; number of entries
        Ccall   |NewFS_create_dir|,1,r6 ; r6 = filing system image handle
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_read_block_size|
        MOV     a1,r1                   ; filename
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_read_block_size|
        ORRVSS  pc,lk,#Vbit
        MOV     r2,r0                   ; block size
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_Func

; r0 reason code:
;
; &08 = rename object (|NewFS_rename|)
;       in:     r1 = pointer to NULL terminated filename
;               r2 = pointer to NULL terminated NEW filename
;               r6 = filing system image handle
;       out:    r1 = rename completion state
;
; &0E = read directory entries (|NewFS_read_dir|)
;       in:     r1 = pointer to NULL terminated wildcarded dirname
;               r2 = data destination memory address
;               r3 = number of objects to read
;               r4 = offset of first object within directory
;               r5 = buffer length
;               r6 = filing system image handle
;       out:    r3 = number of objects read
;               r4 = offset of next item in directory (-1 if end)
;
; &0F = read directory entries and info. (|NewFS_read_dir_info|)
;       in:     r1 = pointer to NULL terminated wildcarded dirname
;               r2 = data destination memory address
;               r3 = number of objects to read
;               r4 = offset of first object within directory
;               r5 = buffer length
;               r6 = filing system image handle
;       out:    r3 = number of records read
;               r4 = offset of next item in directory (-1 if end)
;
; &15 = notification of new image file (|NewFS_image_open|)
;       in:     r1 = FileSwitch handle for file
;               r2 = buffer size for file (0 not known)
;       out:    r1 = filing system image handle
;
; &16 = notification of image file being closed (|NewFS_image_close|)
;       in:     r1 = filing system image handle
;       out:    no conditions
;
; &19 = fill buffer with defect information (|NewFS_defect_list|)
;       in:     r2 = start of buffer in memory
;               r5 = buffer length
;               r6 = filing system image handle
;       out: no conditions
;
; &1A = add a defect into the image mapping (|NewFS_add_defect|)
;       in:     r2 = byte offset to start of defect
;               r6 = filing system image handle
;       out:    no conditions
;
; &1B = read boot option (|NewFS_read_boot_option|)
;       in:     r6 = filing system image handle
;       out:    r2 = boot option (as defined in *OPT 4,n)
;
; &1C = write boot option (|NewFS_write_boot_option|)
;       in:     r2 = new boot option (as defined in *OPT 4,n)
;               r6 = filing system image handle
;       out:    no conditions
;
; &1D = construct used space map (|NewFS_used_space_map|)
;       in:     r2 = buffer for map (pre-filled with 0s)
;               r5 = size of buffer
;               r6 = filing system image handle
;       out:    no conditions
;
; &1E = read free space (|NewFS_read_free_space|)
;       in:     r6 = filing system image handle
;       out:    r0 = free space
;               r1 = size of biggest object that can be created
;               r2 = size of disc (image)
;
; &1F = name disc (|NewFS_namedisc|)
;       in:     r2 = pointer to NULL terminated disc name
;               r6 = filing system image handle
;       out:    no conditions
;
; &20 = update image identity (NewFS_stampimage)
;       in:     r2 = stamp control information
;               r6 = filing system image handle
;       out:    no conditions
;
; &21 = return object identity (NewFS_objectatoffset)
;       in:     r2 = byte offset into image file
;               r3 = pointer to buffer to receive object name
;               r4 = buffer length
;               r6 = filing system image handle
;       out:    r2 = type of object found

        CMP     r0,#func_table_entries
        BGT     NewFS_func_badparameter
        ADD     pc,pc,r0,LSL #2
        &       0                      ; DO NOT REMOVE OR ADD CODE
func_table_start
        B       NewFS_notsupported                ; 00 / 0
        B       NewFS_notsupported                ; 01 / 1
        B       NewFS_notsupported                ; 02 / 2
        B       NewFS_notsupported                ; 03 / 3
        B       NewFS_notsupported                ; 04 / 4
        B       NewFS_notsupported                ; 05 / 5
        B       NewFS_notsupported                ; 06 / 6
        B       NewFS_notsupported                ; 07 / 7
        B       |call_NewFS_rename|               ; 08 / 8
        B       NewFS_notsupported                ; 09 / 9
        B       NewFS_notsupported                ; 0A / 10
        B       NewFS_notsupported                ; 0B / 11
        B       NewFS_notsupported                ; 0C / 12
        B       NewFS_notsupported                ; 0D / 13
        B       |call_NewFS_read_dir|             ; 0E / 14
        B       |call_NewFS_read_dir_info|        ; 0F / 15
        B       NewFS_notsupported                ; 10 / 16
        B       NewFS_notsupported                ; 11 / 17
        B       NewFS_notsupported                ; 12 / 18
        B       NewFS_notsupported                ; 13 / 19
        B       NewFS_notsupported                ; 14 / 20
        B       |call_NewFS_image_open|           ; 15 / 21
        B       |call_NewFS_image_close|          ; 16 / 22
        B       NewFS_notsupported                ; 17 / 23
        B       NewFS_notsupported                ; 18 / 24
        B       |call_NewFS_defect_list|          ; 19 / 25
        B       |call_NewFS_add_defect|           ; 1A / 26
        B       |call_NewFS_read_boot_option|     ; 1B / 27
        B       |call_NewFS_write_boot_option|    ; 1C / 28
        B       |call_NewFS_used_space_map|       ; 1D / 29
        B       |call_NewFS_read_free_space|      ; 1E / 30
        B       |call_NewFS_namedisc|             ; 1F / 31
        B       |call_NewFS_stampimage|           ; 20 / 32
        B       |call_NewFS_objectatoffset|       ; 21 / 33
func_table_end
func_table_entries      *       ((func_table_end - func_table_start) / 4)

NewFS_func_badparameter
        MOV     r0,#badparfunc
        Ccall   |global_error|
        ORRS    pc,lk,#Vbit

|call_NewFS_rename|
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; new filename
        MOV     a3,r6                   ; filing system image handle
        Ccall   |NewFS_rename|
        ORRVSS  pc,lk,#Vbit
        MOV     r1,r0                   ; state
        BICS    pc,lk,#Vbit

|call_NewFS_read_dir|
        STMFD   sp!,{r2}                ; because of OS_GBPB 8 ...
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; data destination
        MOV     a3,r3                   ; number of objects
        MOV     a4,r4                   ; object offset
        Ccall   |NewFS_read_dir|,2,r5-r6
        LDMFD   sp!,{r2}                ; because of OS_GBPB 8 ...
        ORRVSS  pc,lk,#Vbit
        ; r0 = pointer to structure containing return information
        LDMIA   r0,{r3-r4}
        BICS    pc,lk,#Vbit

|call_NewFS_read_dir_info|
        MOV     a1,r1                   ; filename
        MOV     a2,r2                   ; data destination
        MOV     a3,r3                   ; number of objects
        MOV     a4,r4                   ; object offset
        Ccall   |NewFS_read_dir_info|,2,r5-r6
        ORRVSS  pc,lk,#Vbit
        ; r0 = pointer to structure containing return information
        LDMIA   r0,{r3-r4}
        BICS    pc,lk,#Vbit

|call_NewFS_image_open|
        MOV     a1,r1                   ; FileSwitch file handle
        MOV     a2,r2                   ; buffer size
        Ccall   |NewFS_image_open|
        ORRVSS  pc,lk,#Vbit             ; error return
        ; r0 = filing system image handle
        MOV     r1,r0
        BICS    pc,lk,#Vbit

|call_NewFS_image_close|
        MOV     a1,r1                   ; filing system image handle
        Ccall   |NewFS_image_close|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_defect_list|
        MOV     a1,r2                   ; buffer address
        MOV     a2,r5                   ; buffer length
        MOV     a3,r6                   ; filing system image handle
        Ccall   |NewFS_defect_list|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_add_defect|
        MOV     a1,r2                   ; defect address
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_add_defect|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_read_boot_option|
        MOV     a1,r6                   ; filing system image handle
        Ccall   |NewFS_read_boot_option|
        ORRVSS  pc,lk,#Vbit
        MOV     r2,r0                   ; boot option
        BICS    pc,lk,#Vbit

|call_NewFS_write_boot_option|
        MOV     a1,r2                   ; new boot option
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_write_boot_option|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_used_space_map|
        MOV     a1,r2                   ; buffer start address
        MOV     a2,r5                   ; buffer size
        MOV     a3,r6                   ; filing system image handle
        Ccall   |NewFS_used_space_map|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_read_free_space|
        MOV     a1,r6                   ; filing system image handle
        Ccall   |NewFS_read_free_space|
        ORRVSS  pc,lk,#Vbit
        ; r0 = pointer to structure containing return information
        LDMIA   r0,{r0,r1,r2}
        BICS    pc,lk,#Vbit

|call_NewFS_namedisc|
        MOV     a1,r2                   ; NULL terminated discname
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_namedisc|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_stampimage|
        MOV     a1,r2                   ; identity update control information
        MOV     a2,r6                   ; filing system image handle
        Ccall   |NewFS_stampimage|
        ORRVSS  pc,lk,#Vbit
        BICS    pc,lk,#Vbit

|call_NewFS_objectatoffset|
        MOV     a1,r2                   ; byte offset into image
        MOV     a2,r3                   ; object name buffer
        MOV     a3,r4                   ; buffer length
        MOV     a4,r6                   ; filing system image handle
        Ccall   |NewFS_objectatoffset|
        ORRVSS  pc,lk,#Vbit
        MOV     r2,r0                   ; object type at entry offset
        BICS    pc,lk,#Vbit

;****************************************************************************

NewFS_notsupported

; Called when an unrecognised reason code is presented
; There should be no stacked state at this point

        MOV     a1,#notsupported
        Ccall   |global_error|
        ORRS    pc,lk,#Vbit

;****************************************************************************

NewFS_not_enough_stack

; Called when a "Ccall" will fail due to insufficient stack.
; There should be no stacked state at this point

        MOV     a1,#nostack
        Ccall   |global_error|
        ORRS    pc,lk,#Vbit

;****************************************************************************

|write_word|

; Provide a simple function to write a WORD to a non-aligned address
; in:   r0 = byte aligned address
;       r1 = 32bit value to be written

        ANDS    r2,r0,#&03      ; r2 = byte index
        STREQ   r1,[r0,#&00]    ; word-aligned (perform write)
        MOVEQS  pc,lk           ; and exit quickly
        ; non-word aligned data
        STMFD   sp!,{r4,r5,r6,lk}

        BIC     r0,r0,#&03      ; r0 = base word index
        LDMIA   r0,{r4,r5}      ; load the two words our word lives in
        MOV     r2,r2,LSL #3    ; r2 = r2 * 8
        RSB     r3,r2,#32       ; r3 = 32 - r2
        MOV     r4,r4,LSL r3    ; clear the top-bits
        MOV     r6,r1,LSL r2    ; shift up the lo-bits
        ORR     r4,r6,r4,LSR r3 ; re-build the lo-word
        MOV     r5,r5,LSR r2    ; clear the lo-bits
        MOV     r6,r1,LSR r3    ; shift down the top-bits
        ORR     r5,r6,r5,LSL r2 ; re-build the hi-word
        STMIA   r0,{r4,r5}      ; store modified words

        LDMFD   sp!,{r4,r5,r6,pc}^

;****************************************************************************

|load_word|

; Provide a simple function to load a WORD from a non-aligned address
; in:   r0 = byte aligned address

        ANDS    r2,r0,#&03      ; r2 = byte index
        LDREQ   r0,[r0,#&00]    ; word-aligned (perform read)
        MOVEQS  pc,lk           ; and exit quickly
        ; non-word aligned data
        STMFD   sp!,{r4,lk}

        BIC     r0,r0,#&03      ; r0 = base word index
        LDMIA   r0,{r3,r4}      ; load the two words our word lives in
        MOV     r2,r2,LSL #3    ; r2 = r2 * 8        ; shift amount
        RSB     r1,r2,#32       ; r1 = 32 - r2       ; opposite shift amount
        MOV     r0,r3,LSR r2    ; shift down lo-bits from lo-word
        ORR     r0,r0,r4,LSL r1 ; shift up hi-bits from hi-word

        LDMFD   sp!,{r4,pc}^

;****************************************************************************

|validate_buffer|

; Checks range of addresses: r0 = base, r1 = end+1
; Result is TRUE iff every address in the range is valid

        STMFD   sp!,{r2-r12,lk}
        SWI     &3A             ;OS_ValidateAddress
        MOV     r0,#1
        MOVCS   r0,#0
        LDMFD   sp!,{r2-r12,pc}^

;****************************************************************************

 [ TRACE_UPCALLS=1

  EXPORT |UpCallRout|
  IMPORT |NewFS_UpCall|

UpCallRout

  STMFD sp!,{r0-r12,lk}
  MOV a1,sp
  Ccall |NewFS_UpCall|
  LDMFD sp!,{r0-r12,pc}^

 ]

;****************************************************************************

        LTORG

;****************************************************************************

        END
